iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0

第十八天,你已經成功完成了第一個 MVVM 專案,並體驗了 ViewModel 如何解決螢幕旋轉時資料流失的問題。

但你可能會發現,在 MainActivity 中,每次點擊按鈕後,我們還是需要手動地呼叫 setText() 來更新 TextView

如果我們希望 View 能夠自動感知到 ViewModel 裡面的資料有變化,然後自動更新畫面,該怎麼辦呢?這時,我們就需要今天的終極武器:LiveData

什麼是 LiveData

  • 簡單比喻LiveData 就是一個 「有魔法的包裹」
    • 它可以把你的資料(例如:計數器數字)包起來,當這個包裹裡面的東西有變化時,它會自動通知所有觀察它的人。
    • 而你的 View,就像是一個「觀察者」,它會一直盯著這個包裹。只要包裹裡面的資料一變,View 就會立刻更新畫面。
  • 主要特性
    • 可觀察性:當 LiveData 裡的資料改變時,它會自動通知所有觀察者。
    • 生命週期感知LiveData 知道 Activity 的生命週期。它只會向處於活躍狀態的 View (例如:畫面正在顯示) 發送通知,避免記憶體洩漏。

程式碼實作:用 LiveData 實現自動更新

今天,我們要修改昨天的計數器 App,用 LiveData 來實現畫面的自動更新。

1. 修改你的 CounterViewModel.java

打開你的「智慧助理」檔案 CounterViewModel.java。我們要將原本的 int counter 改成 LiveData

`import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; // 新增匯入 MutableLiveData
import androidx.lifecycle.ViewModel;

public class CounterViewModel extends ViewModel {

    // 這是我們「智慧助理」要管理的資料,使用 MutableLiveData
    private MutableLiveData<Integer> _counter = new MutableLiveData<>();

    // 這是給 View 觀察的公開版本
    public LiveData<Integer> counter = _counter;

    // 建構子,設定初始值
    public CounterViewModel() {
        _counter.setValue(0);
    }

    // 增加數字的方法
    public void incrementCounter() {
        // 從包裹中取出舊值
        int currentValue = _counter.getValue() != null ? _counter.getValue() : 0;
        // 增加後,再把新值設定回包裹
        _counter.setValue(currentValue + 1);
    }
}
  • 程式碼解釋
    • MutableLiveData:這是一個可以改變資料的 LiveData 版本。我們用它來修改計數器的值。
    • LiveData:這是一個只讀的 LiveData 版本。我們將它公開給 View 觀察,這樣 View 只能看,不能直接修改資料,保證了資料的安全。
    • _counter.setValue(...):這是改變 LiveData 裡面資料的方法。

2. 修改你的 MainActivity.java (View)

打開你的「被動」角色檔案 MainActivity.java。這次,我們不再需要手動更新 TextView 了。

`import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.Observer; // 新增匯入 Observer

public class MainActivity extends AppCompatActivity {

    private CounterViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 1. 取得 ViewModel 實例
        viewModel = new ViewModelProvider(this).get(CounterViewModel.class);

        // 2. 找到 View 元件
        TextView counterTextView = findViewById(R.id.counterTextView);
        Button incrementButton = findViewById(R.id.incrementButton);

        // 3. 讓 View 開始「觀察」ViewModel 的資料
        viewModel.counter.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer newCounterValue) {
                // 當 ViewModel 裡的數字改變時,這裡的程式碼會自動執行
                // 我們只需要在這裡更新畫面即可
                counterTextView.setText(String.valueOf(newCounterValue));
            }
        });

        // 4. 設定按鈕點擊事件
        incrementButton.setOnClickListener(v -> {
            // 點擊後,我們只需要告訴 ViewModel 執行邏輯
            // 不用手動更新 View 了!
            viewModel.incrementCounter();
        });
    }
}
  • 程式碼解釋
    • viewModel.counter.observe(...):這就是讓 View 成為「觀察者」的關鍵程式碼。它會盯著 viewModel.counter 這個「包裹」。
    • onChanged(...):當 counter 的值發生改變時,這個方法會自動被呼叫,並把新值傳進來。我們只需要在這裡更新 TextView 即可。

3. 執行你的 App!

  • 試著點擊「增加」按鈕,你會發現數字會隨著你的點擊而增加。
  • 關鍵體驗:觀察 MainActivity 的程式碼,你會發現我們在按鈕點擊事件裡,沒有任何一行更新畫面的程式碼!這就是 LiveData 的強大之處。

今日總結

今天我們成功地將 LiveData 應用在 MVVM 模式中,我們學會了:

  • LiveData 是什麼,以及它如何讓 View 自動觀察資料變化。
  • 如何在 ViewModel 中使用 MutableLiveData 來管理可變的資料。
  • 如何在 View 中使用 observe() 方法來觀察 LiveData
  • 最終實現了 資料變動,畫面自動更新 的效果,讓程式碼變得更精簡、更優雅。

你已經掌握了 MVVM 的核心精髓!從明天開始,我們將進入一個更進階的挑戰,讓你將這些概念應用在更複雜的 App 中!

明天見!


上一篇
Day18- MVVM 程式碼實作:計數器 App
下一篇
Day20- 第三階段挑戰:羅馬數字轉換 App (MVVM 準備)
系列文
Android 開發者養成計畫:從程式邏輯到作品集實戰22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言